﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Input;
using ClientOverflow.DataTransferObjects;
using ClientOverflow.ViewModels.Interfaces;
using DynamicControllersGeneration;
using System.Linq;
using Castle.Core;

namespace ClientOverflow.ViewModels.QuestionViewViewModels
{
    /// <summary>
    /// QuestionViewViewModel is a view-model that represents a single question in a view mode. This view-model
    /// supplies all the details about the question, the question answers and all the votings.
    /// This class is an abstract class which is instantiated through a factory method CreateQuestionViewViewModel.
    /// The facotry method creates a dynamic proxy at runtime, the proxy is in charge of routing calls to the model
    /// from the view-model.
    /// The list of answers are wraped as a collection of view models of type QuestionAnswerViewModel. Every
    /// view-model wraps a single answer and in charge of exposing the answer details and voting.
    /// </summary>
    public abstract class QuestionViewViewModel : IQuestionViewViewModel, INotifyPropertyChanged
    {
        public static QuestionViewViewModel CreateQuestionViewViewModel(Question question)
        {
            return viewModelGenerator.Generate<QuestionViewViewModel>(question);
        }

        private Question question;
        private static readonly ViewModelGenerator viewModelGenerator = new ViewModelGenerator();
        private Lazy<PostNewAnswerCommand> postNewAnswerProxy;
        private Lazy<VoteQuestionUpCommand> voteUpProxy;
        private Lazy<VoteQuestionDownCommand> voteDownProxy;

        protected QuestionViewViewModel(Question question)
        {
            InitAnswer(question);
        }

        private void InitAnswer(Question question)
        {
            this.question = question;
            NewAnswer = new NewAnswerViewModel();
            postNewAnswerProxy = new Lazy<PostNewAnswerCommand>(() =>
                                                                    {
                                                                        var postNewAnswerCommand = new PostNewAnswerCommand(question,
                                                                                                                            NewAnswer);
                                                                        postNewAnswerCommand.Executed += OnCommandExecuted;
                                                                        return postNewAnswerCommand;
                                                                    });
            voteUpProxy = new Lazy<VoteQuestionUpCommand>(() =>
                                                              {
                                                                  var voteQuestionUpCommand = new VoteQuestionUpCommand(question);
                                                                  voteQuestionUpCommand.Executed += OnCommandExecuted;
                                                                  return voteQuestionUpCommand;
                                                              });
            voteDownProxy = new Lazy<VoteQuestionDownCommand>(() =>
                                                                  {
                                                                      var voteQuestionDownCommand = new VoteQuestionDownCommand(question);
                                                                      voteQuestionDownCommand.Executed += OnCommandExecuted;
                                                                      return voteQuestionDownCommand;
                                                                  });
            Answers = question.Answers.Select(QuestionAnswerViewModel.CreateQuestionAnswerViewModel).ToList();
            Answers.ForEach(answer => answer.AnswerChosen += RefreshQuestion);
        }

        private void OnCommandExecuted()
        {
            RefreshQuestion();
        }

        private void RefreshQuestion()
        {
            using (var serviceClient = ServicesFactory.CreateClientOverflowServiceClient())
            {
                question = serviceClient.GetAllQuestions().First(question1 => question1.ID == question.ID);
                InitAnswer(question);
            }

            PropertyChanged(this, new PropertyChangedEventArgs("Answers"));
            PropertyChanged(this, new PropertyChangedEventArgs("Votes"));
        }

        public abstract string Title { get; }

        public abstract string Content { get; }
        public IList<IQuestionAnswerViewModel> Answers { get; private set; }

        public INewAnswerViewModel NewAnswer { get; private set; }
        public ICommand PostNewAnswerCommand { get { return postNewAnswerProxy.Value; } }

        public ICommand VoteUpCommand { get { return voteUpProxy.Value; } }
        public ICommand VoteDownCommand { get { return voteDownProxy.Value; } }

        public int Votes { get { return question.UpVotes.Count - question.DownVotes.Count; } }
        public event PropertyChangedEventHandler PropertyChanged = (sender, args) => { };
    }
}